package com.echo.im.repository.offline.support;

import com.echo.im.common.contant.RedisConstants;
import com.echo.im.common.model.mq.OfflineMsgMqInfo;
import com.echo.im.repository.dao.entity.PrivateMessage;
import com.echo.im.repository.dao.mapper.PrivateMessageMapper;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 私信离线消息管理器
 * @author echo
 */
@Component
@Primary
public class PrivateOfflineService extends AbstractOfflineService<PrivateMessage> {

    private static final int MESSAGE_BATCH_SIZE = 500; // 批量操作大小
    private static final int MESSAGE_EXPIRATION_DAYS = 30; // 消息过期时间
    private static final int MAX_OFFLINE_MESSAGES = 1000; // 最大离线消息数
    private static final int MESSAGES_TO_BACKUP = 500; // 每次备份消息数量
    private final PrivateMessageMapper privateMessageMapper;
    private final MySQLOfflineStorage mySQLStorage;
    private final RedisOfflineStorage redisStorage;

    public PrivateOfflineService(MySQLOfflineStorage mysqlStorage,
                                 PrivateMessageMapper privateMessageMapper,
                                 DistributedLockManager lockManager,
                                 RedisOfflineStorage redisStorage) {
        super(lockManager,redisStorage);
        this.mySQLStorage = mysqlStorage;
        this.privateMessageMapper = privateMessageMapper;
        this.redisStorage = redisStorage;
    }

    @Override
    protected String getRedisKeyPrefix() {
        return RedisConstants.IM_PRIVATE_OFFLINE_STORE +":";
    }

    @Override
    protected List<PrivateMessage> fetchAndDeleteMessagesFromStorage(Long userId, Long lastFetchedMessageId, int fetchLimit) {
        List<PrivateMessage> messages = new ArrayList<>();

        // 1. 如果传入了 lastMsgId，则删除该 ID 之前的消息
        if (!lastFetchedMessageId.equals(0L)) {
            // 从 Redis 中增量删除消息
            redisStorage.deleteMessageIds(getRedisKeyPrefix() + userId, lastFetchedMessageId);
            // 从 MySQL 中增量删除消息
            mySQLStorage.deleteMessageIds(userId, lastFetchedMessageId);
        }

        // 2. 从 Redis 中增量拉取 msgIds
        List<String> redisMsgIds = redisStorage.getMessageIds(getRedisKeyPrefix() + userId, lastFetchedMessageId, fetchLimit);
        if (!redisMsgIds.isEmpty()) {
            // 根据 msgIds 从消息主表中获取实际消息内容
            List<PrivateMessage> redisMessages = privateMessageMapper.selectBatchIds(redisMsgIds);
            messages.addAll(redisMessages);
        }

        // 如果 Redis 中的消息不足，则从 MySQL 中拉取剩余的 msgIds
        int remainingSize = fetchLimit - redisMsgIds.size();
        if (remainingSize > 0) {
            List<String> mysqlMsgIds = mySQLStorage.getMessageIds(userId, lastFetchedMessageId, remainingSize);
            if (!mysqlMsgIds.isEmpty()) {
                List<PrivateMessage> mysqlMessages = privateMessageMapper.selectBatchIds(mysqlMsgIds);
                messages.addAll(mysqlMessages);
            }
        }
        return messages;
    }

    @Override
    protected void doStoreMessage(Long userId, String redisKey, Long msgId) {
        redisStorage.addMessageId(redisKey, msgId, MESSAGE_EXPIRATION_DAYS, TimeUnit.DAYS);
        // 检查并备份超出的消息到 MySQL
        redisStorage.checkAndBackupMessageIds(redisKey, userId, MAX_OFFLINE_MESSAGES, MESSAGES_TO_BACKUP, mySQLStorage);
    }

    @Override
    public boolean support(Integer code) {
        return OfflineMsgMqInfo.OfflineMsgEnum.PRIVATE_OFFLINE_MESSAGE.code().equals(code);
    }
}
